package com.hwtx.form.domain.handle;

import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.hwtx.form.util.FormUtil;
import com.hwtx.form.util.JacksonUtil;
import io.geekidea.boot.auth.cache.LoginCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.MessageSource;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

import static com.hwtx.form.util.JacksonUtil.traverseNodes;

@Slf4j
public class FormI18nHandle {

    public interface I18nHandle {
        void handle(ObjectNode parent, TextNode node, String property);
    }

    public static void handle(JsonNode root, MessageSource messageSource, List<String[]> group, Locale locale) {
        long start = System.currentTimeMillis();
        handle(root, group, (parent, node, property) -> handleField(parent, node, property, messageSource, locale));
        log.info("i18n handle time: {}ms", System.currentTimeMillis() - start);
    }

    public static void handle(JsonNode root, List<String[]> group, I18nHandle i18nHandle) {
        for (String[] items : group) {
            List<JacksonUtil.TraverseMatchRule> properties = Arrays.stream(items).map(item -> new JacksonUtil.TraverseMatchRule(item, true)).collect(Collectors.toList());
            if (ArrayUtils.contains(items, "map")) {
                _handleObjectField(root, items[0], properties, i18nHandle);
            } else {
                _handleTextField(root, items[0], properties, i18nHandle);
            }
        }
    }

    private static void _handleTextField(JsonNode root, String field, List<JacksonUtil.TraverseMatchRule> properties,
                                         I18nHandle i18nHandle) {
        traverseNodes(root, field, properties, new JacksonUtil.FindNodeCallback() {
            @Override
            public void handleTextNode(TextNode node, ObjectNode parent, String property) {
                i18nHandle.handle(parent, node, property);
            }
        });
    }

    private static void _handleObjectField(JsonNode root, String field, List<JacksonUtil.TraverseMatchRule> properties,
                                           I18nHandle i18nHandle) {
        traverseNodes(root, field, properties, new JacksonUtil.FindNodeCallback() {
            @Override
            public void handleObjectNode(JsonNode root, ObjectNode node, JsonNode parent, String nodeName) {
                node.fields().forEachRemaining(entry -> {
                    JsonNode value = entry.getValue();
                    if (value.isTextual()) {
                        i18nHandle.handle(node, (TextNode) value, entry.getKey());
                    }
                });
            }

            @Override
            public void handleTextNode(TextNode node, ObjectNode parent, String property) {
                i18nHandle.handle(parent, node, property);
            }
        });
    }

    private static void handleField(ObjectNode parent, TextNode node, String property, MessageSource messageSource, Locale locale) {
        String text = node.asText();
        if (text.startsWith("#i18n")) {
            parent.set(property, TextNode.valueOf(getValue(text, locale, messageSource)));
        }
    }

    private static String getValue(String text, Locale locale, MessageSource messageSource) {
        String key = text.substring(6, text.length() - 1);
        try {
            String value = messageSource.getMessage(key, new Object[]{""}, locale);
            if (StringUtils.isEmpty(value)) {
                throw new RuntimeException("无法获取国际化标识:" + key);
            }
            return value;
        } catch (Exception e) {
            log.error("获取国际化标识:{} 失败", key, e);
        }
        return text;
    }

    public static String getValue(String text) {
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        String localeStr = LoginCache.get().getLocale();
        if (StringUtils.isEmpty(text)) {
            return text;
        }
        String key = FormUtil.getI18nKey(text);
        if (key != null) {
            if (StringUtils.isEmpty(key)) {
                throw new RuntimeException("国际化标识不可为空:" + text);
            }
            Locale locale = Locale.CHINA;
            if (StringUtils.isNotEmpty(localeStr)) {
                locale = Locale.forLanguageTag(localeStr);
            }
            try {
                return messageSource.getMessage(key, new Object[]{""}, locale);
            } catch (Exception ignored) {
            }
        }
        return text;
    }
}
